home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch15 / Solid.cls < prev    next >
Text File  |  1999-06-25  |  8KB  |  319 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "Solid3d"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. ' These Face3d objects are the oriented faces.
  17. Public Faces As Collection
  18.  
  19. Public zmax As Single
  20.  
  21. Public IsConvex As Boolean
  22. Public HideSurfaces As Boolean
  23. ' Sort the faces so those with the largest
  24. ' transformed Z coordinates come first.
  25. '
  26. ' As we switch faces around, we keep track of the
  27. ' number of switches we have made. If it clear we
  28. ' are stuck in an infinite loop, just move the
  29. ' first face to the ordered_faces collection so we
  30. ' can continue.
  31. Public Sub SortFaces()
  32. Dim ordered_faces As Collection
  33. Dim face_1 As Face3d
  34. Dim face_i As Face3d
  35. Dim i As Integer
  36. Dim Xmin As Single
  37. Dim xmax As Single
  38. Dim ymin As Single
  39. Dim ymax As Single
  40. Dim zmin As Single
  41. Dim zmax As Single
  42. Dim xmini As Single
  43. Dim xmaxi As Single
  44. Dim ymini As Single
  45. Dim ymaxi As Single
  46. Dim zmini As Single
  47. Dim zmaxi As Single
  48. Dim overlap As Boolean
  49. Dim switches As Integer
  50. Dim max_switches As Integer
  51.  
  52.     Set ordered_faces = New Collection
  53.  
  54.     ' Pull out any that are culled. These are not
  55.     ' drawn so we can put them at the front of
  56.     ' the ordered_faces collection.
  57.     For i = Faces.Count To 1 Step -1
  58.         If Faces(i).IsCulled Then
  59.             ordered_faces.Add Faces(i)
  60.             Faces.Remove i
  61.         End If
  62.     Next i
  63.  
  64.     ' Order the remaining faces.
  65.     max_switches = Faces.Count
  66.     Do While Faces.Count > 0
  67.         ' Get the first item's extent.
  68.         Set face_1 = Faces(1)
  69.         face_1.GetExtent Xmin, xmax, ymin, ymax, zmin, zmax
  70.  
  71.         ' Compare this face to the others.
  72.         overlap = False     ' In case Face.Count = 0.
  73.         For i = 2 To Faces.Count
  74.             Set face_i = Faces(i)
  75.  
  76.             ' Get item i's extent.
  77.             face_i.GetExtent xmini, xmaxi, ymini, ymaxi, zmini, zmaxi
  78.             overlap = True
  79.             If xmaxi <= Xmin Or xmini >= xmax Or _
  80.                ymaxi <= ymin Or ymini >= ymax Or _
  81.                zmini >= zmax _
  82.             Then
  83.                 ' The extents do not overlap.
  84.                 overlap = False
  85.             ElseIf face_i.IsAbove(face_1) Then
  86.                 ' Face i is all above the plane
  87.                 ' of face 1.
  88.                 overlap = False
  89.             ElseIf face_1.IsBelow(face_i) Then
  90.                 ' Face 1 is all beneath the plane
  91.                 ' of face i.
  92.                 overlap = False
  93.             ElseIf Not face_1.Obscures(face_i) Then
  94.                 ' If face_1 does not lie partly above
  95.                 ' face_i, then there is no problem.
  96.                 overlap = False
  97.             End If
  98.  
  99.             If overlap Then Exit For
  100.         Next i
  101.  
  102.         If overlap And switches < max_switches Then
  103.             ' There's overlap, move face i to the
  104.             ' top of the list.
  105.             Faces.Remove i
  106.             Faces.Add face_i, , 1 ' Before position 1.
  107.             switches = switches + 1
  108.         Else
  109.             ' There's no overlap. Move face 1 to
  110.             ' the ordered_faces collection.
  111.             ordered_faces.Add face_1
  112.             Faces.Remove 1
  113.             max_switches = Faces.Count
  114.             switches = 0
  115.         End If
  116.     Loop ' Loop until we've ordered all the faces.
  117.  
  118.     ' Replace the Faces collection with the
  119.     ' ordered_faces collection.
  120.     Set Faces = ordered_faces
  121. End Sub
  122. ' Set the ZMax value for the solid.
  123. Public Sub SetZmax()
  124. Dim face As Face3d
  125. Dim z_max As Single
  126.  
  127.     zmax = -1E+30
  128.  
  129.     For Each face In Faces
  130.         z_max = face.zmax()
  131.         If zmax < z_max Then zmax = z_max
  132.     Next face
  133. End Sub
  134. ' Create a pyramid with height L and base given
  135. ' by the points in the coord array. Add the
  136. ' faces that make up the pyramid to this solid.
  137. Public Sub Stellate(L As Single, ParamArray coord() As Variant)
  138. Dim x0 As Single
  139. Dim y0 As Single
  140. Dim z0 As Single
  141. Dim x1 As Single
  142. Dim y1 As Single
  143. Dim z1 As Single
  144. Dim x2 As Single
  145. Dim y2 As Single
  146. Dim z2 As Single
  147. Dim x3 As Single
  148. Dim y3 As Single
  149. Dim z3 As Single
  150. Dim Ax As Single
  151. Dim Ay As Single
  152. Dim Az As Single
  153. Dim Bx As Single
  154. Dim By As Single
  155. Dim Bz As Single
  156. Dim nx As Single
  157. Dim ny As Single
  158. Dim nz As Single
  159. Dim num As Integer
  160. Dim i As Integer
  161. Dim pt As Integer
  162.  
  163.     num = (UBound(coord) + 1) \ 3
  164.     If num < 3 Then
  165.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  166.         Exit Sub
  167.     End If
  168.  
  169.     ' (x0, y0, z0) is the center of the polygon.
  170.     x0 = 0
  171.     y0 = 0
  172.     z0 = 0
  173.     pt = 0
  174.     For i = 1 To num
  175.         x0 = x0 + coord(pt)
  176.         y0 = y0 + coord(pt + 1)
  177.         z0 = z0 + coord(pt + 2)
  178.         pt = pt + 3
  179.     Next i
  180.     x0 = x0 / num
  181.     y0 = y0 / num
  182.     z0 = z0 / num
  183.  
  184.     ' Find the normal.
  185.     x1 = coord(0)
  186.     y1 = coord(1)
  187.     z1 = coord(2)
  188.     x2 = coord(3)
  189.     y2 = coord(4)
  190.     z2 = coord(5)
  191.     x3 = coord(6)
  192.     y3 = coord(7)
  193.     z3 = coord(8)
  194.     Ax = x2 - x1
  195.     Ay = y2 - y1
  196.     Az = z2 - z1
  197.     Bx = x3 - x2
  198.     By = y3 - y2
  199.     Bz = z3 - z2
  200.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  201.  
  202.     ' Give the normal length L.
  203.     m3SizeVector L, nx, ny, nz
  204.  
  205.     ' The normal + <x0, y0, z0> gives the point.
  206.     x0 = x0 + nx
  207.     y0 = y0 + ny
  208.     z0 = z0 + nz
  209.  
  210.     ' Build the faces.
  211.     x1 = coord(3 * num - 3)
  212.     y1 = coord(3 * num - 2)
  213.     z1 = coord(3 * num - 1)
  214.     pt = 0
  215.     For i = 1 To num
  216.         x2 = coord(pt)
  217.         y2 = coord(pt + 1)
  218.         z2 = coord(pt + 2)
  219.         AddFace x1, y1, z1, x2, y2, z2, x0, y0, z0
  220.         x1 = x2
  221.         y1 = y2
  222.         z1 = z2
  223.         pt = pt + 3
  224.     Next i
  225. End Sub
  226.  
  227.  
  228. ' Clip faces.
  229. Public Sub ClipEye(ByVal r As Single)
  230. Dim obj As Face3d
  231.  
  232.     For Each obj In Faces
  233.         obj.ClipEye r
  234.     Next obj
  235. End Sub
  236.  
  237. ' Add an oriented face to the solid.
  238. Public Sub AddFace(ParamArray coord() As Variant)
  239. Dim face As Face3d
  240. Dim num As Integer
  241. Dim pt As Integer
  242. Dim i As Integer
  243.  
  244.     num = (UBound(coord) + 1) \ 3
  245.     If num < 3 Then
  246.         MsgBox "Faces in a Solid must contain at least 3 points.", , vbExclamation
  247.         Exit Sub
  248.     End If
  249.  
  250.     Set face = New Face3d
  251.     Faces.Add face
  252.  
  253.     pt = 0
  254.     For i = 1 To num
  255.         face.AddPoints (coord(pt)), (coord(pt + 1)), (coord(pt + 2))
  256.         pt = pt + 3
  257.     Next i
  258. End Sub
  259. ' Perform backface removal on the faces for
  260. ' center of projection at (X, Y, Z).
  261. Public Sub Cull(ByVal X As Single, ByVal Y As Single, ByVal z As Single)
  262. Dim obj As Face3d
  263.  
  264.     For Each obj In Faces
  265.         obj.Cull X, Y, z
  266.     Next obj
  267. End Sub
  268. ' Set or clear the Culled property for all faces.
  269. Property Let Culled(ByVal new_value As Boolean)
  270. Dim obj As Face3d
  271.  
  272.     For Each obj In Faces
  273.         obj.IsCulled = new_value
  274.     Next obj
  275. End Property
  276.  
  277.  
  278.  
  279. ' Apply a transformation matrix which may not
  280. ' contain 0, 0, 0, 1 in the last column to the
  281. ' object.
  282. Public Sub ApplyFull(M() As Single)
  283. Dim obj As Face3d
  284.  
  285.     For Each obj In Faces
  286.         obj.ApplyFull M
  287.     Next obj
  288. End Sub
  289.  
  290. ' Apply a transformation matrix to the object.
  291. Public Sub Apply(M() As Single)
  292. Dim obj As Face3d
  293.  
  294.     For Each obj In Faces
  295.         obj.Apply M
  296.     Next obj
  297. End Sub
  298.  
  299.  
  300. ' Draw the transformed solid on a PictureBox.
  301. Public Sub Draw(ByVal pic As PictureBox, Optional r As Variant)
  302. Dim face As Face3d
  303.  
  304.     ' If we do not know this is a convex solid,
  305.     ' order the faces.
  306.     If HideSurfaces And (Not IsConvex) Then SortFaces
  307.  
  308.     ' Draw the faces.
  309.     For Each face In Faces
  310.         face.Draw pic, r
  311.     Next face
  312. End Sub
  313.  
  314. Private Sub Class_Initialize()
  315.     Set Faces = New Collection
  316. End Sub
  317.  
  318.  
  319.